%{

#define MAX_VISIBILIDAD 20
#define MAX_ENTRADAS 200
#define MAX_TEXTO 100

#define COMIENZO 0
#define FINAL    1


#define CANTIDAD_VARIABLES 5000
#define AUN_SIN_TIPO    -2
#define AUN_SIN_FUNCION -3
#define INICIO_TIPO_FUNCION -4
#define INICIO_TIPO_VPF -5

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
#include "sintactico.tab.h"


#define SIMPLE 0
#define VECTOR 1
#define MATRIZ 2

// DEFINICION DE TIPOS
struct id{
    char *lexema;
    int compuesto;
    int tipo;
    struct textoImpresion *buffer;
};

struct variable{
    struct list_head lista;
    struct list_head listaDeclarados;
    char *lexema;
    int     tipo;
    int compuesto;
};

struct variable_por_funcion{
    char nombre[45];
    int tipo;
    int compuesto;
    int funcion; // nombre de la funcion a que pertenece
};


struct argumento{
    struct list_head lista;
    int posicion;
    int tipo;
    char *lexema;
};

struct argumentos{
    struct argumento *args;
    int cArg;    
    struct textoImpresion *buffer;
};

struct funcion{
    struct list_head lista;
    struct argumentos *listaArgumentos;
    char *lexema;
    int retorno;
    int prototipo;
};

struct textoImpresion{
    struct list_head lista;
    char *texto;
};



// VARIABLES GLOBALES
extern FILE *yyin;
FILE *out;
extern int yylineno;

int traducir=1;
int scope=0;

struct list_head *tablaVariables[MAX_VISIBILIDAD] = {NULL};
struct list_head *tablaFunciones = NULL;

struct variable_por_funcion variables_por_funcion[CANTIDAD_VARIABLES];
int numero_funcion = 0;
int indice_vpf = 0;
yydebug = 0;

FILE *archivo_de_salida;
// es global para que las otras funciones le vean

extern int traducir;
extern int yylineno;
extern int scope;

extern struct list_head *tablaVariables[MAX_VISIBILIDAD];
extern struct list_head *tablaFunciones;
extern struct list_head *listaConstantes;

extern struct variable_por_funcion variables_por_funcion[CANTIDAD_VARIABLES];


// PROTOTIPOS
void nueva_vpf (char *nombre, int tipo, int compuesto, int funcion);
void yyprint (char *imprime);
void yyerror(char *);

void imprimirTexto(char *texto);
void imprimirBuffer(struct textoImpresion *listaTexto);
struct textoImpresion *agregarTextoAntes(char *texto,struct textoImpresion *listaTexto);
void agregarTextoDespues(char *texto,struct textoImpresion *listaTexto);
void agregarLista(struct textoImpresion *cabeza,struct textoImpresion *resto);
struct id* crearNodoId(void);
int verificaMain(void);
void agregarDeclaracion(struct list_head *nuevo,struct list_head *lista);
void imprimirFuncion(struct funcion *f, int n);
int compararArgumentos(struct argumentos *real, struct argumentos *llamada,char *lexema);
void agregarNodoArgumento(int tipo,char *lexema,struct argumentos *a);
struct argumentos* crearNodoArgumentos(void);
struct funcion* crearNodoFuncion(int retorno, char *lexema, struct argumentos *args);
void agregarNodoFuncion(struct funcion *f);
struct funcion *buscarNodoFuncion(char *s);
struct funcion *buscarNodoFuncionR(char *s);
struct variable* crearNodoVariable(void);
void agregarVariable(struct variable *v);
struct variable *buscaVariableScope(char *s,int scope);
struct variable *buscaVariable(char *s);
void asignarDeclaradosTipo(int tipo,struct list_head *lista);
void incrementarScope(void);
void decrementarScope(void);
void errorFatal(char *msj);
void errorSemantico(char *lexema,char *msj);



%}

%union {
    char *lexema;
    struct funcion *fun;
    int tipo;
    struct argumentos *args;
    struct list_head *lista;
    struct id *id;
};


%token <tipo> INTEGER CHAR FLOAT VOID IF ELSE FOR WHILE DO
%token <lexema> ID CARACTER ENTERO REAL LITERAL PRINTF
%token TIPO_VACIO
%token TIPO_ERROR
%token RETURN
%nonassoc IFX
%nonassoc ELSE
%left AND OR
%right '!'
%left '=' '<' '>' EQUALEQUAL DISCTINCT MINEQUAL MAYEQUAL 
%left '+' '-' MINUSEQUAL PLUSEQUAL PLUSPLUS MINUSMINUS 
%left '*' '/' '%' MULEQUAL DIVEQUAL 
%right UMINUS
%type <id> variable expresion proposicion proposicionDoWhile listaProposiciones listaDeclaraciones proposicionCompuesta asignacion expresionAsignacion reglaElse
%type <fun> funcion 
%type <tipo> declaracion tipo 
%type <args> listaParams listaExpresiones
%type <lista> listaVar listaVariables


%%
inicio:
    listaFunciones
        {
            if(!verificaMain())
                errorSemantico(""," No existe una funcion main\n");
        }

    |   listaVar listaFunciones
        {
            if(!verificaMain())
                errorSemantico(""," No existe una funcion main\n");
        }

    ;
        

listaVar: 
    declaracion

    |   tipo ID '(' listaParams ')' ';'
        {
            if((struct variable *)buscaVariable($2)) {
                errorSemantico($2," intentando redefinir como un tipo de simbolo distinto\n");
            } else {
                struct funcion *f = (struct funcion *)buscarNodoFuncion($2);
                if(f!=NULL) {
                    errorSemantico($2," ya existe esa funcion ");
                } else {
                    if($4!=NULL){
                        f = (struct funcion *)crearNodoFuncion($1,$2,$4);
                        f->prototipo = 1;
                        agregarNodoFuncion(f);
                    }
                }
            }
            decrementarScope(); 
        }

    |   listaVar declaracion

    |   listaVar tipo ID '(' listaParams ')' ';'
        { 
            if((struct variable *)buscaVariable($2)) {
                errorSemantico($2," intentando redefinir como un tipo de simbolo distinto\n");
            } else {
                struct funcion *f = (struct funcion *)buscarNodoFuncion($2);
                if(f != NULL) {
                    errorSemantico($2," ya existe esa funcion ");
                } else {
                    if($5 != NULL) {
                        f = (struct funcion *)crearNodoFuncion($1,$2,$5);
                        f->prototipo = 1;
                        agregarNodoFuncion(f);
                    }
                }
            }
            decrementarScope(); 
        }

    |   error declaracion  { yyerrok; };

    |   error tipo ID '(' listaParams ')' ';'
        { 
            if((struct variable *)buscaVariable($3)) {
                errorSemantico($3," intentando redefinir como un tipo de simbolo distinto\n");
            } else {
                struct funcion *f = (struct funcion *)buscarNodoFuncion($3);
                if(f != NULL) {
                    errorSemantico($3," ya existe esa funcion ");
                } else {
                    if($5!=NULL) {
                        f = (struct funcion *)crearNodoFuncion($2,$3,$5);
                        f->prototipo = 1;
                        agregarNodoFuncion(f);
                    }
                }
            }
            decrementarScope(); 
            { yyerrok; }
            ;
        }

    ;


listaFunciones:
    funcion
    |   listaFunciones funcion 
    ;
    

funcion:
    tipo ID '(' listaParams ')' proposicionCompuesta
    {
        if((struct variable *)buscaVariable($2)) {
            errorSemantico($2," intentando redefinir como un tipo de simbolo distinto\n");
            $$ = NULL;
        } else {
            struct funcion *f = (struct funcion *)buscarNodoFuncion($2);

            if(f!=NULL && buscarNodoFuncionR($2)) {
                errorSemantico($2," ya existe esa funcion ");
                $$ = NULL;
            } else {
                if(f!=NULL && !compararArgumentos(f->listaArgumentos,$4,f->lexema)) {
                    errorSemantico($2," no se puede definir una funcion que no coincida con el prototipo");
                    $$ = NULL;
                } else {
                    if($4!=NULL && $6!=NULL) {
                        agregar_funcion_vpf (numero_funcion);
                        f = (struct funcion *)crearNodoFuncion($1,$2,$4);
                        f->prototipo=0;
                        agregarNodoFuncion(f);
                        $$ = f;
                        
                        imprimirFuncion(f, numero_funcion);
                        imprimirBuffer($6->buffer);
                        imprimirTexto("\n\0");
                        numero_funcion++;
                    }

                }
            }
        }
        decrementarScope();
    }

    |   tipo ID '(' error ')' proposicionCompuesta
    {
        yyerrok;
    }

    ;
             

listaParams:
    tipo ID
    {
        incrementarScope();
        /* creacion de la variable */
        if((struct variable *)buscaVariableScope($2,scope)) {
            errorSemantico($2,"Variable not declared\n");
            $$ = NULL;
        } else {
            struct variable *v = (struct variable *)crearNodoVariable();
            v->lexema=strdup($2);
            v->tipo = $1;
            v->compuesto=SIMPLE;
            agregarVariable(v); 

            /* creacion de la lista de argumentos */
            $$=(struct argumentos*)crearNodoArgumentos();
            agregarNodoArgumento($1,$2,$$);
        }      
    }

    | listaParams ',' tipo ID
    {
        if((struct variable *)buscaVariableScope($4,scope)) {
            errorSemantico($4,"Variable not declared\n");
            $$ = NULL;
        } else {
            struct variable *v = (struct variable *)crearNodoVariable();
            v->lexema=strdup($4);
            v->tipo = $3;
            v->compuesto=SIMPLE;
            agregarVariable(v);
            if($1 != NULL) {
                agregarNodoArgumento($3,$4,$1);
                $$=$1;
            } else {
                $$ = NULL;
            }
        }
    }

    | VOID
    {
        incrementarScope();
        $$=(struct argumentos*)crearNodoArgumentos();
        agregarNodoArgumento(TIPO_VACIO,"",$$);
    }

    | listaParams ',' error
    {
        yyerrok;
        $$ = NULL;
    }

    | /* producion -> vacia*/
    {
        incrementarScope();
        $$ = (struct argumentos*)crearNodoArgumentos();
        agregarNodoArgumento(TIPO_VACIO,"",$$);
    }

    ;


tipo:
    INTEGER
    {
        $$ = ENTERO;
    }

    | CHAR
    {
        $$=CARACTER;
    }

    | FLOAT
    {
        $$=REAL;
    }

    | VOID
    {
        $$=TIPO_VACIO;
    }

    ;            


variable:
    ID
    {      
        $$=(struct id*)crearNodoId();
        $$->lexema=strdup($1);
        $$->compuesto=SIMPLE;

        
        $$->buffer = (struct textoImpresion*)agregarTextoAntes("\0",$$->buffer);
        
        agregarTextoDespues($1,$$->buffer);
    }

    | ID '[' expresion ']'
    {
        $$=(struct id*)crearNodoId();
        $$->lexema=strdup($1);
        $$->compuesto=VECTOR;
        
        
        $$->buffer = (struct textoImpresion*)agregarTextoAntes("\0",$$->buffer);
        agregarTextoDespues($1,$$->buffer);
        agregarTextoDespues("[\0",$$->buffer);
        
        if($3!=NULL)
            agregarLista($3->buffer,$$->buffer);
        
        
        agregarTextoDespues("]\0",$$->buffer);
    }

    | ID '[' expresion ']''[' expresion ']'
    {
        $$=(struct id*)crearNodoId();
        $$->lexema=strdup($1);
        $$->compuesto=MATRIZ;

        $$->buffer = (struct textoImpresion*)agregarTextoAntes("\0",$$->buffer);
        agregarTextoDespues($1,$$->buffer);
        agregarTextoDespues("[\0",$$->buffer);
        
        if($3!=NULL)
            agregarLista($3->buffer,$$->buffer);
        

        agregarTextoDespues(",\0",$$->buffer);

        
        if($6!=NULL)
            agregarLista($6->buffer,$$->buffer);
        
        agregarTextoDespues("]\0",$$->buffer);
    }        

    ;


expresion:
    variable
    {
        struct variable *v = (struct variable *)buscaVariable($1->lexema);

        if(v==NULL) {
            errorSemantico($1->lexema,"Variable not declared\n");
            $$=NULL;
        } else {
            if($1->compuesto != v->compuesto) {
                errorSemantico($1->lexema," Type not valid\n");
                $$=NULL;
            } else {
                $$=$1;
                $$->tipo=v->tipo;
            }
        }

    }

    | ENTERO
    { 
        $$=(struct id*)crearNodoId();

        
        $$->buffer = (struct textoInforme *)agregarTextoAntes($1,$$->buffer);
        $$->tipo = ENTERO;

    }

    | REAL
    {
        $$=(struct id*)crearNodoId();
        
        
        $$->buffer = (struct textoInforme *)agregarTextoAntes($1,$$->buffer);
        $$->tipo = REAL;
    }

    | CARACTER
    {
        $$=(struct id*)crearNodoId();
        
        
        $$->buffer = (struct textoInforme *)agregarTextoAntes($1,$$->buffer);
        $$->tipo = CARACTER;
    }

    | LITERAL
    {  
        $$=(struct id*)crearNodoId();
        
        
        $$->buffer = (struct textoInforme *)agregarTextoAntes($1,$$->buffer);
        $$->tipo = LITERAL;
    }

    | expresion '+' expresion
    {
        if($1!=NULL && $3!=NULL) {
            if($1->tipo==$3->tipo) {
                $$=$1;
                
                agregarTextoDespues("+\0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            } else {
                errorSemantico("","Se intento sumar dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion '-' expresion
    {
        if($1!=NULL && $3!=NULL) {
            if($1->tipo==$3->tipo) {
                $$=$1; 
                
                agregarTextoDespues("-\0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            } else {
                errorSemantico("","Se intento restar dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion '*' expresion
    {
        if($1!=NULL && $3!=NULL) {
            if($1->tipo==$3->tipo){
                $$=$1;
                
                agregarTextoDespues("*\0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            } else {
                errorSemantico("","Se intento multiplicar dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion '/' expresion
    {
        if($1!=NULL && $3!=NULL) {
             if($1->tipo==$3->tipo) {
                $$=$1;
                
                switch ($1->tipo) {
                    case ENTERO:
                        agregarTextoDespues(" div \0",$$->buffer);
                        break;
                    case REAL:
                        agregarTextoDespues("/\0",$$->buffer);
                        break;
                    default:
                        errorSemantico("","Pascal no admite operacion de division con otros tipos que no sean Integer y Double.\n");
                        $$=NULL;
                }
                agregarLista($3->buffer,$$->buffer);
             } else {
                errorSemantico("","Se intento dividir dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion '%' expresion
    {
        if($1!=NULL && $3!=NULL){
             if($1->tipo==$3->tipo){
                $$=$1;
                
                agregarTextoDespues(" mod \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
             }else{
                errorSemantico("","Se intento modulo dos tipos diferentes\n");
                $$=NULL;
            }
        
        }else
            $$=NULL;
    }

    | expresion '<' expresion
    {
        if($1!=NULL && $3!=NULL){
             if($1->tipo==$3->tipo){
                $$=$1;
                
                agregarTextoDespues(" < \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
             }else{
                errorSemantico("","Se intento menor que de dos tipos diferentes\n");
                $$=NULL;
            }
        
        }else
            $$=NULL;
    }

    | expresion '>' expresion
    {
        if($1!=NULL && $3!=NULL) {
            if($1->tipo==$3->tipo) {
                $$=$1;
                
                agregarTextoDespues(" > \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            } else {
                errorSemantico("","Se intento mayor que en dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | '-' expresion %prec UMINUS
    {
        if($2!=NULL){
            $$=(struct id*)crearNodoId();
            
            $$->buffer=(struct textoInforme *)agregarTextoAntes("-\0",$$->buffer);
            agregarLista($2->buffer,$$->buffer);
            $$->tipo=$2->tipo;
         }else
            $$=NULL;
         
     }

    | '(' expresion ')'
    {
        if($2!=NULL) {
            $$=(struct id*)crearNodoId();
            
            $$->buffer=(struct textoInforme *)agregarTextoAntes("(\0",$$->buffer);
            agregarLista($2->buffer,$$->buffer);
            
            agregarTextoDespues(")\0",$$->buffer);
            $$->tipo = $2->tipo;
         }else
            $$=NULL;
    }

    | expresion AND expresion
    {
        if($1!=NULL && $3!=NULL){
            if($1->tipo==$3->tipo){
                $$=$1;
                
                agregarTextoDespues(" and \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            }else{
                errorSemantico("","Se intento AND de dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion EQUALEQUAL expresion
    {
        if($1!=NULL && $3!=NULL){
            if($1->tipo==$3->tipo){
                $$=$1;
                
                agregarTextoDespues(" = \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            }else{
                errorSemantico("","Se intento comparar de dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion DISCTINCT expresion
    {
        if($1!=NULL && $3!=NULL){
            if($1->tipo==$3->tipo){
                $$=$1;
                
                agregarTextoDespues(" <> \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            }else{
                errorSemantico("","Se intento comparar de dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion MINEQUAL expresion
    {
        if($1!=NULL && $3!=NULL){
            if($1->tipo==$3->tipo){
                $$=$1;
                
                agregarTextoDespues(" <= \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            } else {
                errorSemantico("","Se intento comparar de dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion MAYEQUAL expresion
    {
        if($1!=NULL && $3!=NULL){
            if($1->tipo==$3->tipo){
                $$=$1;
                
                agregarTextoDespues(" >= \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            }else{
                errorSemantico("","Se intento comparar de dos tipos diferentes\n");
                $$=NULL;
            }
        }else
            $$=NULL;
    }                           

    | expresion OR expresion
    {
        if($1!=NULL && $3!=NULL){
            if($1->tipo==$3->tipo){
                $$=$1;
                
                agregarTextoDespues(" or \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            }else{
                errorSemantico("","Se intento OR de dos tipos diferentes\n");
                $$=NULL;
            }
        }else
            $$=NULL;
    }

    | '!' expresion
    {
        if($2!=NULL){
            $$=(struct id*)crearNodoId();
            
            $$->buffer=(struct textoInforme *)agregarTextoAntes(" not \0",$$->buffer);
            agregarLista($2->buffer,$$->buffer);
            $$->tipo=$2->tipo;
         }else
            $$=NULL;
    }

    | ID '(' listaExpresiones ')'
    {
        if((struct variable *)buscaVariable($1)){
            errorSemantico($1," no es una funcion\n");
        }else{                                        
            struct funcion *f = (struct funcion *)buscarNodoFuncion($1);
            if(f==NULL){
                errorSemantico($1," No existe la funcion ");
                $$=NULL;
            }else{
                if($3!=NULL){
                    if(compararArgumentos(f->listaArgumentos,$3,$1)){
                        $$=(struct id*)crearNodoId();
                        
                        $$->buffer=(struct textoInforme *)agregarTextoAntes($1,$$->buffer);
                        agregarTextoDespues("(\0",$$->buffer);
                        if($3->cArg>0)
                            agregarLista($3->buffer,$$->buffer);
                        
                        agregarTextoDespues(")\0",$$->buffer);
                        $$->tipo = f->retorno;
                    }else{
                        $$=NULL;
                    }
                }else
                    $$=NULL;
            }
        }
    }

    |  PRINTF '(' listaExpresiones ')'
    {
        if($3!=NULL){
            $$=(struct id*)crearNodoId();
            
            $$->buffer=(struct textoInforme *)agregarTextoAntes("writeLn\0",$$->buffer);
            
            agregarTextoDespues("(\0",$$->buffer);
            agregarLista($3->buffer,$$->buffer);
            agregarTextoDespues(")\0",$$->buffer);
        } else
            $$=NULL;
    }

    ;         

proposicionDoWhile:  '{' listaProposiciones '}' {
                                        if($2!=NULL){
                                        int i = 0;
                                        $$=(struct id*)crearNodoId();
                                        
                                        
                                        for(i=0;i<scope;i++)
                                            $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
                                        
                                        
                                        
                                        agregarTextoDespues("\n\0",$$->buffer);
                                        
                                        agregarLista($2->buffer,$$->buffer);
                                        
                                        agregarTextoDespues("\n\0",$$->buffer);
                                        
                                        for(i=0;i<scope;i++)
                                            agregarTextoDespues("\t\0",$$->buffer);
                                        }else{
                                            $$=NULL;
                                        }
                                        
                                     }  

proposicion: ';'
    {
        int i=0;
        $$=(struct id*)crearNodoId();
        
        for(i=0;i<scope;i++)
            $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
        
                            
        agregarTextoDespues(";\0",$$->buffer);
        agregarTextoDespues("\n\0",$$->buffer);
     }

    | expresion ';'
    {
        int i=0;
        
        if($1!=NULL){
            $$=(struct id*)crearNodoId();
            
            
            for(i=0;i<scope;i++)
                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
            
            agregarLista($1->buffer,$$->buffer);
            
            agregarTextoDespues(";\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
        }else
            $$=NULL;
    }

    | asignacion ';'
    {
        int i=0;
        
        if($1!=NULL){
            $$=(struct id*)crearNodoId();
            
            
            for(i=0;i<scope;i++)
                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
            
            agregarLista($1->buffer,$$->buffer);
            
            agregarTextoDespues(";\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
        } else
            $$=NULL;
    }

    | IF '(' expresionAsignacion ')' { incrementarScope(); } proposicion { decrementarScope(); } reglaElse
    {
        if($3!=NULL && $6!=NULL){
            int i=0;
            
            $$=(struct id*)crearNodoId();
            
            
            for(i=0;i<scope;i++)
                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
            
            
            agregarTextoDespues("if \0",$$->buffer);
            agregarTextoDespues("(\0",$$->buffer);
            agregarLista($3->buffer,$$->buffer);
            agregarTextoDespues(") then\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
            agregarLista($6->buffer,$$->buffer);
            if($8!=NULL)
                agregarLista($8->buffer,$$->buffer);
                agregarTextoDespues("\n\0",$$->buffer);
        } else
            $$=NULL;
    }

    | FOR '(' expresionAsignacion ';' expresionAsignacion ';' expresionAsignacion ')' { incrementarScope(); } proposicion 
    {
        if($3!=NULL && $5!=NULL && $7!=NULL &&$10!=NULL){
            int i=0;
            
            $$=(struct id*)crearNodoId();
            
                for(i=0;i<scope;i++)
                    $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
            
            
            agregarTextoDespues("for\0",$$->buffer);
            agregarTextoDespues("(\0",$$->buffer);
            agregarLista($3->buffer,$$->buffer);
            agregarTextoDespues(";\0",$$->buffer);
            agregarLista($5->buffer,$$->buffer);
            agregarTextoDespues(";\0",$$->buffer);
            agregarLista($7->buffer,$$->buffer);
            agregarTextoDespues(")\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
            agregarLista($10->buffer,$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
        } else
            $$=NULL;
    
        decrementarScope(); 
    }

    | WHILE '(' expresionAsignacion ')' { incrementarScope(); } proposicion 
    { 
        if($3!=NULL && $6!=NULL){
            int i=0;
        
            $$=(struct id*)crearNodoId();
            
            for(i=0;i<scope;i++)
                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
        
            
            agregarTextoDespues("while\0",$$->buffer);
            agregarTextoDespues("(\0",$$->buffer);
            agregarLista($3->buffer,$$->buffer);
            agregarTextoDespues(") do\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
            agregarLista($6->buffer,$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
        
        } else
            $$=NULL;

        decrementarScope(); 
    }

    | DO { incrementarScope(); } proposicionDoWhile WHILE '(' expresionAsignacion ')' ';'
    { 
        if($3!=NULL && $6!=NULL){
            int i=0;
        
            $$=(struct id*)crearNodoId();
            
            for(i=0;i<scope;i++)
                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
        
            
            agregarTextoDespues("repeat\n\0",$$->buffer);
            agregarLista($3->buffer,$$->buffer);   
            
            agregarTextoDespues("until (not(\0",$$->buffer);
            agregarLista($6->buffer,$$->buffer);
            agregarTextoDespues("));\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
        
        } else
            $$=NULL;

        decrementarScope(); 
    }
    
    | proposicionCompuesta

    | RETURN expresionAsignacion ';'
    {
        if($2!=NULL){
            int i=0;
        
            $$=(struct id*)crearNodoId();
            
            for(i=0;i<scope;i++)
                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
            
                    
            agregarTextoDespues("return \0",$$->buffer);
            agregarLista($2->buffer,$$->buffer);
            agregarTextoDespues(";\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
        } else
            $$=NULL;
    }

    | RETURN ';'
    {
        int i=0;
        $$=(struct id*)crearNodoId();
        
        for(i=0;i<scope;i++)
            $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
        
        
    //    agregarTextoDespues("\0",$$->buffer);
      //  agregarTextoDespues(";\0",$$->buffer);
     }

    | error ';'
    {
        $$=NULL; 
        yyerrok; 
    }

    ;


proposicionCompuesta:
         '{' '}'                 {
                                                int i =0;
                                                $$=(struct id*)crearNodoId();
                                                
                                                
                                                for(i=0;i<scope;i++)
                                                    $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
                                                
                                                
                                                /*agregarTextoDespues("{\0",$$->buffer);
                                                
                                                agregarTextoDespues("\n\0",$$->buffer);
                                                
                                                for(i=0;i<scope;i++)
                                                    agregarTextoDespues("\t\0",$$->buffer);
                                                
                                                agregarTextoDespues("}\0",$$->buffer);*/
                                 }                 
        | '{' listaProposiciones '}' {
                                        if($2!=NULL){
                                        int i = 0;
                                        $$=(struct id*)crearNodoId();
                                        
                                        
                                        for(i=0;i<scope;i++)
                                            $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
                                        
                                        
                                        agregarTextoDespues("begin\0",$$->buffer);
                                        
                                        agregarTextoDespues("\n\0",$$->buffer);
                                        
                                        agregarLista($2->buffer,$$->buffer);
                                        
                                        agregarTextoDespues("\n\0",$$->buffer);
                                        
                                        for(i=0;i<scope;i++)
                                            agregarTextoDespues("\t\0",$$->buffer);
        
                                        agregarTextoDespues("end;\0",$$->buffer);
                                        }else{
                                            $$=NULL;
                                        }
                                        
                                     }                    
        | '{' listaDeclaraciones '}'        {     
                                                int i =0;
                                                $$=(struct id*)crearNodoId();
                                                
                                                
                                                for(i=0;i<scope;i++)
                                                    $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
                                                
                                                
                                                agregarTextoDespues("begin\0",$$->buffer);
                                                
                                                agregarTextoDespues("\n\0",$$->buffer);
                                                
                                                for(i=0;i<scope;i++)
                                                    agregarTextoDespues("\t\0",$$->buffer);
                                                
                                                agregarTextoDespues("end\0",$$->buffer);
                                            }        
        | '{' listaDeclaraciones listaProposiciones '}' {   
                                                            if($3!=NULL){
                                                            int i = 0;
                                                            $$=(struct id*)crearNodoId();
                                                            
                                                            
                                                            for(i=0;i<scope;i++)
                                                                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
                                                            
                                                            
                                                            agregarTextoDespues("begin\n\0",$$->buffer);
                                                            //agregarTextoDespues("var\n\0",$$->buffer);

                                                            //agregarLista($2->buffer, $$->buffer);
                                                            //agregarTextoDespues("\nbegin\n\0",$$->buffer);
                                                            agregarLista($3->buffer, $$->buffer);
                                                            
                                                            agregarTextoDespues("\n\0",$$->buffer);
                                                            
                                                            for(i=0;i<scope;i++)
                                                                agregarTextoDespues("\t\0",$$->buffer);
                            
                                                            agregarTextoDespues("end;\0",$$->buffer);
                                                            }else{
                                                                $$=NULL;
                                                            }
                                                            
                                                        }        
        | error '}' { $$=NULL; yyerrok; }  
        ;            
            
expresionAsignacion:
                expresion { $$=$1; 
                          }
                | asignacion {
                               $$=$1;
                             }
                ;
            
declaracion: tipo listaVariables ';'                    {  
                                                        if($1!=TIPO_ERROR && $2!=NULL){
                                                            asignarDeclaradosTipo($1,$2);
                                                            $$=TIPO_VACIO;
                                                            agregar_tipo_vpf($1);
                                                        }else{
                                                            $$=TIPO_ERROR;
                                                        }
                                                     }
            | tipo listaVariables '=' expresion ';' { 
                                                      if($4!=NULL){
                                                          if($1!=$4->tipo){
                                                                errorSemantico(""," la expresion no es del tipo de las variables");
                                                                $$=TIPO_ERROR;
                                                           }else if($2!=NULL){
                                                                asignarDeclaradosTipo($1,$2);
                                                                agregar_tipo_vpf($1);
                                                                $$=TIPO_VACIO;
                                                           }
                                                       }else{
                                                            $$=TIPO_ERROR;
                                                       }
                                                    }
            ;                    

listaVariables:
        variable                 {     
                                        if((struct variable *)buscaVariableScope($1->lexema,scope)){
                                            errorSemantico($1->lexema,"Variable not declared\n");
                                            $$=NULL;
                                        }else{
                                            struct variable *v = (struct variable *)crearNodoVariable();
                                             v->lexema=strdup($1->lexema);
                                             v->compuesto=$1->compuesto;
                                             agregarVariable(v); 
                                             $$=&v->listaDeclarados;
                                             nueva_vpf ($1->lexema, AUN_SIN_TIPO, $1->compuesto, AUN_SIN_FUNCION);
                                        }
                                         
                                 }
        | listaVariables ',' variable {   if((struct variable *)buscaVariableScope($3->lexema,scope)){
                                            errorSemantico($3->lexema,"Variable not declared\n");
                                            $$=NULL;
                                          }else{
                                                struct variable *v = (struct variable *)crearNodoVariable();
                                                 v->lexema=strdup($3->lexema);
                                                 v->compuesto=$3->compuesto;
                                                 agregarVariable(v); 
                                                 nueva_vpf ($3->lexema, AUN_SIN_TIPO, $3->compuesto, AUN_SIN_FUNCION);

                                                if($1!=NULL){
                                                    agregarDeclaracion(&v->listaDeclarados,$1);
                                                    $$=$1;
                                                }else{
                                                    $$=NULL;
                                                }
                                           }
                                           
                                      }
        ;
            
listaExpresiones:  expresionAsignacion {      
                                if($1!=NULL){
                                     $$=(struct argumentos*)crearNodoArgumentos();
                                     agregarNodoArgumento($1->tipo,"",$$);
                                     $$->buffer=$1->buffer;
                                 }else{
                                    $$=NULL;
                                 }
                             }
                 | listaExpresiones ',' expresionAsignacion { 
                                                     if($1!=NULL){
                                                        $$=$1;
                                                        if($3!=NULL){
                                                            agregarNodoArgumento($3->tipo,"",$1);
                                                            
                                                            agregarTextoDespues(",\0",$$->buffer);
                                                            agregarLista($3->buffer,$$->buffer);
                                                        }
                                                     }else{
                                                        $$=NULL;
                                                     }
                                                  }
                 |             {    $$=(struct argumentos*)crearNodoArgumentos();
                                 agregarNodoArgumento(TIPO_VACIO,"",$$);
                                 
                            }
                 |  listaExpresiones ',' error { yyerrok;
                                                    if($1!=NULL)
                                                        $$=$1;
                                                    else
                                                        $$=NULL;
                                                }
                 ;            

listaDeclaraciones: declaracion
                | listaDeclaraciones declaracion
                ;                 
                 
listaProposiciones: proposicion {
                                    if($1!=NULL){
                                        $$=$1;
                                    }else{
                                        $$=NULL;
                                    }
                                }
                | listaProposiciones proposicion {
                                                    if($1!=NULL){
                                                        $$=$1;
                                                        if($2!=NULL){
                                                            agregarLista($2->buffer,$1->buffer);
                                                        }
                                                    }else{
                                                        $$=NULL;
                                                    }
                                                 }
                ;
                                        
reglaElse:   ELSE { incrementarScope(); } proposicion
            {
                if($3!=NULL){
                
                $$=(struct id*)crearNodoId();
                
                
                $$->buffer=(struct textoInforme *)agregarTextoAntes("else\0",$$->buffer);
                
                
                agregarTextoDespues("\n\0",$$->buffer);
                
                agregarLista($3->buffer,$$->buffer);
                
                }else{
                    $$=NULL;
                }
                
                decrementarScope(); 
            }
             | { $$=NULL; }  %prec IFX
             ; 
            
asignacion: variable '=' expresion {

                                   if($1!=NULL && $3!=NULL){
                                   
                                   struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema," no fue declarada\n");
                                          $$=NULL;
                                       }else{
                                            if(v->tipo != $3->tipo || v->compuesto != $1->compuesto){
                                                     errorSemantico(v->lexema,"Type not valid\n");
                                                    $$=NULL;
                                            }else{
                                                $$=$1;
                                                
                                                agregarTextoDespues(" := \0",$$->buffer);
                                                agregarLista($3->buffer,$$->buffer);
                                            }
                                        }
                                    
                                    }
                                    
                                    
                                  }
            | variable PLUSPLUS {  
                                   if($1!=NULL){
                                        struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema," no fue declarada\n");
                                          $$=NULL;
                                       }else{
                                                $$=$1;
                                                
                                                agregarTextoDespues(" := \0",$$->buffer);
                                                agregarTextoDespues($1->lexema,$$->buffer);
                                                agregarTextoDespues(" + 1\0",$$->buffer);
                                                
                                        }
                                    }else{
                                        $$=NULL;
                                    }
                                }
            | variable MINUSMINUS {  
                                    if($1!=NULL){
                                        struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema," no fue declarada\n");
                                          $$=NULL;
                                       }else{
                                                $$=$1;
                                                
                                                agregarTextoDespues(" := \0",$$->buffer);
                                                agregarTextoDespues($1->lexema,$$->buffer);
                                                agregarTextoDespues(" - 1\0",$$->buffer);
                                        }
                                    }else{
                                        $$=NULL;
                                    }
                                }
            | variable PLUSEQUAL expresion {
                                    
                                  if($1!=NULL && $3!=NULL){
                                        struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema," no fue declarada\n");
                                          $$=NULL;
                                       }else{
                                                if(v->tipo == $3->tipo){
                                                    $$=$1;
                                                    
                                                    agregarTextoDespues("+=\0",$$->buffer);
                                                    agregarLista($3->buffer,$$->buffer);
                                                }else{
                                                    errorSemantico($1->lexema,"Type not valid\n");
                                                    $$=NULL;
                                                }
                                        }
                                    }else{
                                        $$=NULL;
                                    }
                                    
                                    
                                  }
            | variable MULEQUAL expresion {
            
                                   if($1!=NULL && $3!=NULL){
                                        struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema,"Not declared\n");
                                          $$=NULL;
                                       }else{
                                                if(v->tipo == $3->tipo){
                                                    $$=$1;
                                                    
                                                    agregarTextoDespues("*=\0",$$->buffer);
                                                    agregarLista($3->buffer,$$->buffer);
                                                }else{
                                                    errorSemantico($1->lexema,"Type not valid\n");
                                                    $$=NULL;
                                                }
                                        }
                                    }else{
                                        $$=NULL;
                                    }
                                    
                                    
                                  }
            | variable DIVEQUAL expresion {
                                    if($1!=NULL && $3!=NULL){
                                        struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema,"Not declared\n");
                                          $$=NULL;
                                       }else{
                                                if(v->tipo == $3->tipo){
                                                    $$=$1;
                                                    
                                                    agregarTextoDespues("/=\0",$$->buffer);
                                                    agregarLista($3->buffer,$$->buffer);
                                                }else{
                                                    errorSemantico($1->lexema,"Type not valid\n");
                                                    $$=NULL;
                                                }
                                        }
                                    }else{
                                        $$=NULL;
                                    }
                                    
                                  }
            | variable MINUSEQUAL expresion {
                                    if($1!=NULL && $3!=NULL){
                                        struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema," : Not declared\n");
                                          $$=NULL;
                                       }else{
                                                if(v->tipo == $3->tipo){
                                                    $$=$1;
                                                    
                                                    agregarTextoDespues("-=\0",$$->buffer);
                                                    agregarLista($3->buffer,$$->buffer);
                                                }else{
                                                    errorSemantico($1->lexema,": Type not valid\n");
                                                    $$=NULL;
                                                }
                                        }
                                    }else{
                                        $$=NULL;
                                    }
                                    
                                    
                                  }
            ;
%%

void 
yyprint (char *imprime)
{
    fprintf(stderr, "%s", imprime);
}

void
yyerror(char *tipo_de_error)
{
    printf("%s: linea %d, cerca de \"%s\".\n", tipo_de_error, yylineno, yylval.lexema);
}


void
nueva_vpf (char *nombre, int tipo, int compuesto, int funcion)
{
    strcpy (variables_por_funcion[indice_vpf].nombre, nombre);
    variables_por_funcion[indice_vpf].tipo = tipo;
    variables_por_funcion[indice_vpf].compuesto = compuesto;
    variables_por_funcion[indice_vpf].funcion = funcion;
    
    indice_vpf++;
}

void
agregar_tipo_vpf (int tipo)
{
    int i;
    
    for (i = 0; i < CANTIDAD_VARIABLES; i++)
        if (variables_por_funcion[i].tipo == AUN_SIN_TIPO) 
            variables_por_funcion[i].tipo = tipo;
}

void
agregar_funcion_vpf (int funcion)
{
    int i;
    
    for (i = 0; i < CANTIDAD_VARIABLES; i++)
        if (variables_por_funcion[i].funcion == AUN_SIN_FUNCION) 
            variables_por_funcion[i].funcion = funcion;
}


void imprimirTexto(char *texto){
    fprintf(archivo_de_salida,texto);
}


void
inicializar_vpf ()
{
    int i;
    
    for (i = 0; i < CANTIDAD_VARIABLES; i++) {
        variables_por_funcion[i].tipo = INICIO_TIPO_VPF;
        variables_por_funcion[i].funcion = INICIO_TIPO_FUNCION;
    }
}

void imprimirBuffer(struct textoImpresion *listaTexto){
    struct textoImpresion *t=NULL;
    
    if(listaTexto!=NULL){
        t = list_entry(&listaTexto->lista, struct textoImpresion, lista);
            imprimirTexto(t->texto);
        list_for_each_entry(t,&listaTexto->lista,lista){
                imprimirTexto(t->texto);
        }
    }
}

struct textoImpresion *agregarTextoAntes(char *texto,struct textoImpresion *listaTexto){
    struct textoImpresion *t=NULL;
    
    //fprintf(stderr, "agregarTextoAntes: %s\n", texto);
    if((t=(struct textoImpresion*)malloc(sizeof(struct textoImpresion)))==NULL)
        errorFatal("Memory full");
    
    INIT_LIST_HEAD(&t->lista);
    t->texto=strdup(texto);
    
    if(listaTexto == NULL){
        listaTexto = t;
        return t;
    }
    
    list_add(&t->lista,&listaTexto->lista);
    return t;
}

void agregarTextoDespues(char *texto,struct textoImpresion *listaTexto){
    struct textoImpresion *t=NULL;

    //fprintf(stderr, "agregarTextoDespues: %s\n", texto);
    if((t=(struct textoImpresion*)malloc(sizeof(struct textoImpresion)))==NULL)
        errorFatal("Memory full");
    
    INIT_LIST_HEAD(&t->lista);
    t->texto=strdup(texto);
    
    list_add_tail(&t->lista,&listaTexto->lista);
}

void agregarLista(struct textoImpresion *cabeza,struct textoImpresion *resto){
    struct list_head *a = &cabeza->lista;
    struct list_head *f = &resto->lista;
    struct list_head *ap = a->prev;
    struct list_head *fp = f->prev;
    
    ap->next = f;
    f->prev = ap;
    a->prev = fp;
    fp->next = a;
    
}

struct id* crearNodoId(void){
    
    struct id *v=NULL;
    if((v=(struct id*)malloc(sizeof(struct id)))==NULL)
        errorFatal("Memory full");

    v->buffer=NULL;        
    
    return v;
}

int verificaMain(void){
    struct funcion *f = buscarNodoFuncion("main");
    
    return (f && !f->prototipo);

}

struct variable *buscaVariableScope(char *s,int scope){
    
    struct variable *v=NULL;
    
    if(tablaVariables[scope] == NULL)
        return NULL;
        
    v = list_entry(tablaVariables[scope], struct variable, lista);
    if(strcmp(s,v->lexema) == 0){
            return v;
    }
    
    list_for_each_entry(v,tablaVariables[scope],lista) {
        if(strcmp(s,v->lexema) == 0){
            return v;
        }
    }
    
    return NULL;
    
}

struct variable *buscaVariable(char *s){
    int scopeActual = scope;
    struct variable *v;
    
    while(scopeActual>0){
        v = buscaVariableScope(s,scopeActual);
        if(v!=NULL)
            return v;
        scopeActual--;
    };
    
    v = buscaVariableScope(s,scopeActual);
    if(v!=NULL)
        return v;
    
    return NULL;
}

void agregarDeclaracion(struct list_head *nuevo,struct list_head *lista){
    
    list_add(nuevo,lista);
}

void asignarDeclaradosTipo(int tipo,struct list_head *lista){
    struct variable *v;

    v = list_entry(lista,struct variable,listaDeclarados);
        v->tipo = tipo;
    
    list_for_each_entry(v,lista,listaDeclarados)
        v->tipo = tipo;
    
}


void
imprimirvariablesdelafuncion(int nro)
{
    int i;
    char bandera = 0;
    
    for (i = 0; i < CANTIDAD_VARIABLES; i++)
        if ((variables_por_funcion[i].funcion == nro)) {
            bandera = 1;
            break;
        }
            
    if (!bandera) return;
    
    imprimirTexto("var\n\0");
    for (i = 0; i < CANTIDAD_VARIABLES; i++)
        if (variables_por_funcion[i].funcion == nro) {
            imprimirTexto(variables_por_funcion[i].nombre);
            imprimirTexto(" : \0");
            switch (variables_por_funcion[i].tipo) {
                case ENTERO:
                    imprimirTexto("Integer;\n\0");
                    break;
                case CARACTER:
                    imprimirTexto("Char;\n\0");
                    break;
                case REAL:
                    imprimirTexto("Real;\n\0");
                    break;
            }
        }
    
}

void imprimirFuncion(struct funcion *f, int nrofuncion){
    int j=0;
    struct argumento *v;
    
    imprimirTexto("\n\0");
    imprimirTexto("function\0");
    imprimirTexto(" ");
    imprimirTexto(f->lexema);
    imprimirTexto("(\0");
    
    v = list_entry(&f->listaArgumentos->args->lista,struct argumento,lista);
        if(v->tipo != TIPO_VACIO){
            j++;
            // imprimirTexto("$\0");
            imprimirTexto(v->lexema);
            imprimirTexto(": \0");
            switch (v->tipo) {
                case ENTERO:
                    imprimirTexto("Integer\0");
                    break;
                case CARACTER:
                    imprimirTexto("Char\0");
                    break;
                case REAL:
                    imprimirTexto("Real\0");
                    break;
            }
            imprimirTexto("; \0");
        }
    
    list_for_each_entry(v,&f->listaArgumentos->args->lista,lista){
        if(v->tipo != TIPO_VACIO){
            j++;
            // imprimirTexto("$\0");
            imprimirTexto(v->lexema);
            imprimirTexto(": \0");
            switch (v->tipo) {
                case ENTERO:
                    imprimirTexto("Integer \0");
                    break;
                case CARACTER:
                    imprimirTexto("Char \0");
                    break;
                case REAL:
                    imprimirTexto("Real \0");
                    break;
            }
            if (list_entry(v->lista.next, typeof(*v), lista) != &f->listaArgumentos->args->lista)
                imprimirTexto("; \0");
        }
    }
    
    if(j>0)
        fseek(archivo_de_salida,-1,SEEK_CUR);
    imprimirTexto("):\0");
    switch (f->retorno) {
        case ENTERO:
            imprimirTexto("Integer;\0");
            break;
        case CARACTER:
            imprimirTexto("Char;\0");
            break;
        case REAL:
            imprimirTexto("Real;\0");
            break;
    }
    imprimirTexto("\n\0");
    imprimirvariablesdelafuncion(nrofuncion);
}


int compararArgumentos(struct argumentos *real, struct argumentos *llamada,char *lexema){
    struct list_head *listaReal;
    struct list_head *listaLlamada;
    int i=0;
    
    struct argumento *tmpReal;
    struct argumento *tmpLlamada;
    
    if(real->cArg != llamada->cArg){
        errorSemantico(lexema, " Number of args not correct\n");
        return 0;
    }
    
    listaReal= &real->args->lista;
    listaLlamada = &llamada->args->lista;
    
    tmpReal = list_entry(listaReal,struct argumento,lista);
    tmpLlamada = list_entry(listaLlamada,struct argumento,lista);
        
    if(tmpReal->tipo != tmpLlamada->tipo || tmpReal->posicion != tmpLlamada->posicion){
        errorSemantico(lexema," Argument type not valid.\n");
        return 0;
    }
    
    for(i;i<real->cArg;i++){
        listaReal = listaReal->next;
        listaLlamada = listaLlamada->next;
    
        tmpReal = list_entry(listaReal,struct argumento,lista);
        tmpLlamada = list_entry(listaLlamada,struct argumento,lista);
            
        if(tmpReal->tipo != tmpLlamada->tipo || tmpReal->posicion != tmpLlamada->posicion){
            errorSemantico(lexema," Argument type not valid.\n");
            return 0;
        }
    }
    return 1;
}

void agregarVariable(struct variable *v){
   
    if(tablaVariables[scope] == NULL){
        tablaVariables[scope] = &v->lista;
        return;
    }
    
    list_add(&v->lista,tablaVariables[scope]);
}

void agregarNodoArgumento(int tipo,char *lexema,struct argumentos *a){
    
    struct argumento *arg=NULL;
    
    if((arg=(struct argumento*)malloc(sizeof(struct argumento)))==NULL)
        errorFatal("Memory full");
    
    INIT_LIST_HEAD(&arg->lista);

    arg->tipo = tipo;
    arg->posicion = a->cArg;
    arg->lexema = strdup(lexema);
    
    if(tipo != TIPO_VACIO)
        a->cArg++;
    
    if(a->args == NULL){
        a->args = arg;
        return;
    }
    
    list_add_tail(&arg->lista,&a->args->lista);
}


struct argumentos* crearNodoArgumentos(void){
    
    struct argumentos *v=NULL;
    if((v=(struct argumentos*)malloc(sizeof(struct argumentos)))==NULL)
        errorFatal("Memory full");
    
    v->args=NULL;
    v->cArg=0;
    v->buffer=NULL;
    return v;
}

struct funcion* crearNodoFuncion(int retorno, char *lexema, struct argumentos *args){
    
    struct funcion *f=NULL;
    if((f=(struct funcion*)malloc(sizeof(struct funcion)))==NULL)
        errorFatal("Memory full");
    
    INIT_LIST_HEAD(&f->lista);    
    
    f->retorno = retorno;
    f->lexema = strdup(lexema);
    f->listaArgumentos = args;
    
    return f;
}

void agregarNodoFuncion(struct funcion *f){
    
    if(tablaFunciones == NULL){
        tablaFunciones = &f->lista;
        return;
    }
    
    list_add(&f->lista,tablaFunciones);
}

struct funcion *buscarNodoFuncion(char *s){
    struct funcion *f=NULL;
    
    if(tablaFunciones == NULL)
        return NULL;
        
    f = list_entry(tablaFunciones, struct funcion, lista);
    if(strcmp(s,f->lexema) == 0){
            return f;
    }
    
    list_for_each_entry(f,tablaFunciones,lista) {
        if(strcmp(s,f->lexema) == 0){
            return f;
        }
    }
    
    return NULL;
    
}

struct funcion *buscarNodoFuncionR(char *s){
    struct funcion *f=NULL;
    
    if(tablaFunciones == NULL)
        return NULL;
        
    f = list_entry(tablaFunciones, struct funcion, lista);
    if(strcmp(s,f->lexema) == 0 && !f->prototipo){
            return f;
    }
    
    list_for_each_entry(f,tablaFunciones,lista) {
        if(strcmp(s,f->lexema) == 0){
            return f;
        }
    }
    
    return NULL;
    
}

struct variable* crearNodoVariable(void){
    
    struct variable *v=NULL;
    if((v=(struct variable*)malloc(sizeof(struct variable)))==NULL)
        errorFatal("Memory full");
    
    INIT_LIST_HEAD(&v->lista);    
    INIT_LIST_HEAD(&v->listaDeclarados);
    return v;
}

void incrementarScope(){
    if(scope < MAX_VISIBILIDAD) 
        scope++;
        
}

void decrementarScope(){
    if(scope > 0){
        tablaVariables[scope] = NULL;
        scope--;
    }
    
}

void errorFatal(char *msj)
{
    printf("%s\n",msj);
    exit(EXIT_FAILURE);
}


void errorSemantico(char *lexema,char *msj)
{
       traducir = 0;
    
    printf("Error Semantico: Linea %d: %s %s\n", yylineno, lexema, msj);
}



char *
nombre_archivo_salida(char *nombre)
{
    int len;
    char *nombre_de_salida;

    len = strlen(nombre);
    nombre_de_salida = malloc(sizeof(char) * (len + 3));
    strncpy(nombre_de_salida, nombre, len - 1);
    strcat(nombre_de_salida, "pas");
    
    return (nombre_de_salida);
}

void
escribir_inicio_programa(char *nombre)
{
    int len;
    char *nombre_del_programa;
    
    len = strlen(nombre);
    nombre_del_programa = malloc((len - 4) * sizeof(char));
    strncpy(nombre_del_programa, nombre, len - 4);
    fprintf(archivo_de_salida, "program %s;\n", nombre_del_programa);
    free(nombre_del_programa);
}

int
main (int argc, char **argv)
{
    FILE *archivo_de_entrada;
    char *salida;
    if (argc < 2) {
        return 1;
    }

 
    if ((archivo_de_entrada = fopen(argv[1], "r")) == NULL) {
        printf("Error al abrir fuente.\n");
        return -1;
    } 
    yyrestart(archivo_de_entrada);

    salida = nombre_archivo_salida(argv[1]);
    if ((archivo_de_salida = fopen(salida, "w")) == NULL) {
        printf("Error al crear output.\n");
        fclose(archivo_de_entrada);
        return -1;
    }
    
    escribir_inicio_programa(salida);
    inicializar_vpf();
    yyparse();

    if(traducir) {
        fprintf(archivo_de_salida,"\nbegin\n\twriteLn(main());\nend.\n");
        printf("\nOk. Output: %s.\n", salida);
        fclose(archivo_de_salida);
        fclose(archivo_de_entrada);
        return 0;
   }

    fclose(archivo_de_salida);
    fclose(archivo_de_entrada);
    printf("Error en la traduccion.\n");
    return 0;
}


